package cn.groupmarket.types.design.framework.link.model2.chain;


import lombok.Data;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;

@Slf4j
public class LinkedList<E> implements ILink<E>{
    @Getter
    private final String name;

    transient int size = 0;
    transient Node<E> first;
    transient Node<E> last;

    public LinkedList(String name) {
        this.name = name;
    }

    void linkFirst(E e) {
        final Node<E> f = first;
        final Node<E> newNode = new Node<>(null,e,f);
        first = newNode;
        if(f == null){
            last = newNode;
        }else{
            f.prev = newNode;
        }
        size ++;
    }

    void linkLast(E e) {
        final Node<E> l = last;
        final Node<E> newNode = new Node<>(l,e,null);
        last = newNode;
        if(l == null){
            first = newNode;
        }else{
            l.next = newNode;
        }
        size ++;
    }

    E unlink(Node<E> node) {
        final E element = node.item;
        final Node<E> prev = node.prev;
        final Node<E> next = node.next;
        if(prev == null){
            first = next;
        }else {
            prev.next = next;
            node.prev = null;
        }
        if(next == null){
            last = prev;
        }else{
            next.prev = prev;
            node.next = null;
        }
        node.item = null;
        size--;
        return element;
    }

    Node<E> node(int index) {
        if(index < 0 || index >= size){
            return null;
        }
        if(index < (size/2)){
            Node<E> node = first;
            for(int i = 0 ; i < index ; i++){
                node = node.next;
            }
            return node;
        }else {
            Node<E> node = last;
            for(int i = size-1; i > index ; i--){
                node = node.prev;
            }
            return node;
        }
    }

    @Override
    public boolean add(E e) {
        linkLast(e);
        return false;
    }

    @Override
    public boolean addFirst(E e) {
        linkFirst(e);
        return false;
    }

    @Override
    public boolean addLast(E e) {
        linkLast(e);
        return false;
    }

    @Override
    public boolean remove(Object o) {
        if(o == null){
            for(Node<E> f = first; f != null;f = f.next){
                if(f.item == null){
                    unlink(f);
                    return true;
                }
            }
        }else{
            for(Node<E> f = first; f != null;f = f.prev){
                if(f.item.equals(o)){
                    unlink(f);
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    public E get(int index) {
        return node(index).item;
    }

    @Override
    public void printLinkList() {
        if(first == null || last == null || size == 0){
            log.info("链表为空");
        }else{
            List<E> nodeList = new ArrayList<E>();
            for(Node<E> x = first; x != null;x = x.next){
                nodeList.add(x.item);
            }
            log.info("{}",nodeList);
        }
    }

    protected  static class Node<E>{
        E item;
        Node<E> next;
        Node<E> prev;
        public Node(Node<E> next,E item, Node<E> prev) {
            this.item = item;
            this.next = next;
            this.prev = prev;
        }
    }
}
